﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Diagnostics.Contracts;

namespace SimpleIR
{
	/// <summary>
	/// Class representing pointers.
	/// These may be stored in the heap, can never be to the interior of an object or struct and can never point to fixed locations.
	/// </summary>
	public sealed class IRPtrType : IRType
	{
		private readonly IRType m_target;

		private readonly bool m_isspecialnullptr;
		
		[ContractInvariantMethod]
		private void ObjectInvariant()
		{
			Contract.Invariant(this.m_isspecialnullptr | (this.m_target != null));
			Contract.Invariant(this.m_isspecialnullptr | (this.m_target is IRClassType));
		}

		public IRPtrType(string tnamespace, string tbasename, TypeQualifiers tqual, IRType trgt)
			: base(tnamespace, tbasename, tqual)
		{
			Contract.Requires(!String.IsNullOrEmpty(tbasename));
			Contract.Requires(trgt != null);
			Contract.Requires(trgt is IRClassType);

			this.m_target = trgt;
			this.m_isspecialnullptr = false;
		}

		public static IRPtrType MakeSpecialNullPtr()
		{ return new IRPtrType(); }

		//Only for making the special null pointer
		private IRPtrType()
			: base(null, "null", TypeQualifiers.PublicTag | TypeQualifiers.BuiltinTag)
		{
			this.m_target = null;
			this.m_isspecialnullptr = true;
		}

		public IRClassType PtrTargetType 
		{ 
			get 
			{
				Contract.Ensures(Contract.Result<IRClassType>() != null);

				return (IRClassType)this.m_target; 
			} 
		}

		public bool IsNullPointer
		{ get { return this.m_isspecialnullptr; } }

		public override void ProcessBuiltinInfoAsNeeded()
		{ ;}
	}

	/// <summary>
	/// Class representing references.
	/// These may NOT be stored in the heap, locations of this type can NEVER BE NULL or may ONLY be assigned to ONCE.
	/// However, they can be to the interior of an object or struct and can point to fixed locations.
	/// </summary>
	public sealed class IRReferenceType : IRType
	{
		private readonly IRType m_target;

		[ContractInvariantMethod]
		private void ObjectInvariant()
		{
			Contract.Invariant(this.m_target != null);
			Contract.Invariant(!(this.m_target is IRReferenceType));
		}

		public IRReferenceType(string tnamespace, string tbasename, TypeQualifiers tqual, IRType trgt)
			: base(tnamespace, tbasename, tqual)
		{
			Contract.Requires(!String.IsNullOrEmpty(tbasename));
			Contract.Requires(trgt != null);
			Contract.Requires(!(trgt is IRReferenceType));

			this.m_target = trgt;
		}

		public IRType ReferenceTargetType
		{
			get
			{
				Contract.Ensures(Contract.Result<IRType>() != null);

				return this.m_target;
			}
		}

		public override void ProcessBuiltinInfoAsNeeded()
		{ ;}
	}
}
